/* HPAudit: Always use strict mode : hp-specs-use-strict-mode : 1 : 0 : issue469.ts */
"use strict";
const OperatorLevels = { 
    '+': 0,
    '-': 0,
    '*': 1,
    '/': 1,
  }
const OperatorHandlers = { 
    '+': (firstOperand, secondOperand) => (parseFloat(firstOperand) + parseFloat(secondOperand)).toFixed(getFloatNum(firstOperand, secondOperand, '+')),
    '-': (firstOperand, secondOperand) => (firstOperand - secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '-')),
    '*': (firstOperand, secondOperand) => (firstOperand * secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '*')),
    '/': (firstOperand, secondOperand) => (firstOperand / secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '/')),
  }
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 15 : issue469.ts */
function getFloatNum(firstOperand, secondOperand, oprate): number {
  let result = 0
  /* HPAudit: Declare unchanged variables as const : hp-performance-unchanged-const-vars : 1 : 17 : issue469.ts */
  const oneString = (new String(firstOperand)).toString()
  /* HPAudit: Declare unchanged variables as const : hp-performance-unchanged-const-vars : 1 : 18 : issue469.ts */
  const otherString = (new String(secondOperand)).toString()
  let firstNum = 0
  if (oneString.indexOf('.') !== - 1) {
    firstNum = oneString.split('.')[1].length
  }
  let secondNum = 0
  if (otherString.indexOf('.') !== - 1) {
    secondNum = otherString.split('.')[1].length
  }
  if (oprate === '+' || oprate === '-') {
    result = Math.max(firstNum, secondNum)
  }
  if (oprate === '*') {
    result = firstNum + secondNum
  }
  if (oprate === '/') {
    result = (firstNum + otherString.length) > 3 ? (firstNum + otherString.length) : 3
  }
  return result
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 39 : issue469.ts */
function calcSuffixExpression(expression) {
  const numberStack = []
  while (expression.length) {
    /* HPAudit: Declare unchanged variables as const : hp-performance-unchanged-const-vars : 1 : 44 : issue469.ts */
    const element = expression.shift()
    if (! isOperator(element)) {
      numberStack.push(element)
    } else {
      const firstStackElement = numberStack.pop()
      const secondStackElement = numberStack.pop()
      /* HPAudit: Avoid using closures - consider using parameters instead : hp-performance-no-closures : 1 : 50 : issue469.ts */
      const result = OperatorHandlers[element](secondStackElement, firstStackElement)
      if (result.length > 15) {
        numberStack.push(parseFloat(result).toExponential())
      } else {
        numberStack.push(result)
      }
    }
  }
  return numberStack[0]
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 61 : issue469.ts */
function toSuffixExpression(expression) {
  const operatorStack = []
  const suffixExpression = []
  let topOperator
  /* HPAudit: Do not access a const property in a heavy loop : hp-performance-no-const-prop-in-heavy-loop : 1 : 65 : issue469.ts */
  const T1 = operatorStack[operatorStack.length - 1];
  for (let index = 0, size = expression.length; index < size; ++index) {
    const element = expression[index]
    if (element === '(') {
      operatorStack.push(element)
      continue
    }
    if (element === ')') {
      if (operatorStack.length) {
        let operator = operatorStack.pop()
        while (operator !== '(') {
          suffixExpression.push(operator)
          operator = operatorStack.pop()
        }
      }
      continue
    }
    if (isOperator(element)) {
      if (! operatorStack.length) {
        operatorStack.push(element)
      } else {
        topOperator = T1
        if (! isGrouping(topOperator) && ! isPrioritized(element, topOperator)) {
          while (operatorStack.length) {
            suffixExpression.push(operatorStack.pop())
          }
        }
        operatorStack.push(element)
      }
      continue
    }
    suffixExpression.push(element)
  }
  while (operatorStack.length) {
    suffixExpression.push(operatorStack.pop())
  }
  return suffixExpression
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 103 : issue469.ts */
function parseInfixExpression(inputContent) {
  const size = inputContent.length
  const lastIndex = size - 1
  let singleChar = ''
  const expression = []
  for (let index = 0; index < size; index++) {
    const element = inputContent[index]
    if (isGrouping(element)) {
      if (singleChar !== '') {
        expression.push(singleChar)
        singleChar = ''
      }
      expression.push(element)
    } else if (isOperator(element)) {
      if (isSymbol(element) && (index === 0 || inputContent[index - 1] === '(')) {
        singleChar += element
      } else {
        if (singleChar !== '') {
          expression.push(singleChar)
          singleChar = ''
        }
        if (index !== lastIndex) {
          expression.push(element)
        }
      }
    } else {
      singleChar += element
    }
    if (index === lastIndex && singleChar !== '') {
      expression.push(singleChar)
    }
  }
  return expression
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 138 : issue469.ts */
function isPrioritized(firstOperator, secondOperator): boolean {
  /* HPAudit: Avoid using closures - consider using parameters instead : hp-performance-no-closures : 1 : 139 : issue469.ts */
  return OperatorLevels[firstOperator] > OperatorLevels[secondOperator]
}
export function isOperator(operator) {
  return (operator === '+' || operator === '-' || operator === '*' || operator === '/')
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 148 : issue469.ts */
function isSymbol(symbol): boolean {
  return symbol === '+' || symbol === '-'
}
/* HPAudit: Explicitly declare return types of functions and methods : hp-specs-explicit-return-types : 1 : 152 : issue469.ts */
function isGrouping(operator): boolean {
  return operator === '(' || operator === ')'
}
export function calc(inputContent) {
  const infixExpression = parseInfixExpression(inputContent)
  const suffixExpression = toSuffixExpression(infixExpression)
  return calcSuffixExpression(suffixExpression)
}
